/**
 * 
 */
package org.rollinitiative.d20.items;

import java.util.HashMap;

import org.apache.commons.configuration.XMLConfiguration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xmlbeans.XmlException;
import org.exist.xmldb.XQueryService;
import org.rollinitiative.d20.entity.InvalidEntityException;
import org.rollinitiative.d20.items.Armor.EncumberanceCategory;
import org.rollinitiative.d20.persist.PersistenceBridge;
import org.rollinitiative.d20.schema.item.ItemType;
import org.xmldb.api.base.Collection;
import org.xmldb.api.base.ResourceSet;
import org.xmldb.api.base.XMLDBException;

/**
 * This class bridges the domains of data content and data persistence for Equipment related
 * content.
 * 
 * @author bebopjmm
 * 
 * TODO Determine if separate collections should be maintained for major groups (i.e. armor and weapons)
 */
public class ItemContentBridge extends PersistenceBridge
{
    final static Log LOG = LogFactory.getLog(ItemContentBridge.class);

    Collection itemCollection;
    
    HashMap <String, ItemType> itemCache = new HashMap<String, ItemType>();

    public ItemContentBridge(XMLConfiguration config)
    {
        super(config);
    }
    
    /**
     * Retrieves the item collection for the specified campaign.
     * 
     * @param campaign
     */
    public void loadCollection(String campaign)
    {
        try {
            connect(campaign);
            itemCollection = retrieveCollection("items");
            xqueryService = (XQueryService) itemCollection.getService("XQueryService", "1.0");
        } catch (XMLDBException ex) {
            LOG.error("Failed to load the races collection");
        }
    }
    
    /**
     * This method constructs a new instance of an Item of the type designated by itemTypeID.
     * NOTE: currently only armor is supported.
     * 
     * @param itemTypeID uniqueID of the ItemType to create an instance Item from
     * @return a new Item based on ItemType
     * @throws InvalidEntityException when no ItemType of itemTypeID can be retrieved.
     */
    public Item makeInstanceOf(String itemTypeID) throws InvalidEntityException
    {
        ItemType itemType = retrieveItem(itemTypeID);
        if (itemType.isSetArmor())
            return makeArmorInstance(itemType);
        else {
            LOG.error("Current Item Type is not supported: " + itemType.getName());
            return null;
        }     
    }
    
    /**
     * This method constructs a new instance of armor of the type represented by itemType.
     * 
     * @param itemType Type specification for armor instance
     * @return the new armor instance
     */
    Armor makeArmorInstance(ItemType itemType)
    {
        LOG.debug("Instantiating new armor item: " + itemType.getName());
        Armor item = new Armor();
        item.setName(itemType.getName());
        item.setWeight(itemType.getWeight());
        item.setCost(itemType.getCost());
        item.setArmorBonus(itemType.getArmor().getDefenseBonus().intValue());
        item.setSkillPenalty(itemType.getArmor().getSkillPenalty().intValue());
        
        EncumberanceCategory category = EncumberanceCategory.mapArmorCategory(itemType.getArmor().xgetCategory());
        item.setEncumberance(category);
        
        return item;
    }

    /**
     * Retrieves the designated item, checking against the local cache first.
     * 
     * @param itemTypeID identifier of item to retrieve
     * @return xmlbean matching the provided itemID
     * @throws InvalidEntityException
     */
    ItemType retrieveItem(String itemTypeID) throws InvalidEntityException
    {
     // Check Cache first
        if (itemCache.containsKey(itemTypeID)) {
            LOG.debug("Cache contained requested item: " + itemTypeID);
            return itemCache.get(itemTypeID);
        }
        
        try {
            LOG.debug("Querying for requested item: " + itemTypeID);
            String itemQuery = config.getString("itemBridge.queries.itemByID");
            itemQuery = itemQuery.replace("#ID#", itemTypeID);
            LOG.debug("Parameterized Query: " + itemQuery);
            ResourceSet results = query(itemQuery);
            if (results.getSize() < 1) {
                throw new InvalidEntityException("Specified Item not Found: " + itemTypeID);
            }

            ItemType item = ItemType.Factory.parse(results.getResource(0).getContent().toString(),
                    xmlOptions);
            itemCache.put(itemTypeID, item);
            return item;
        } catch (XmlException e) {
            LOG.error("Failure to parse requested item: )" + itemTypeID, e);
            throw new InvalidEntityException("Failure to retrieve specified Item: " + itemTypeID);
        } catch (XMLDBException e) {
            LOG.error("Failure to parse requested item: )" + itemTypeID, e);
            throw new InvalidEntityException("Failure to retrieve specified Item: " + itemTypeID);
        }
    }
}
